package com.peng.herostory.login;

import com.alibaba.fastjson.JSONObject;
import com.peng.herostory.MySqlSessionFactory;
import com.peng.herostory.async.AsyncThreadProcessor;
import com.peng.herostory.async.IAsyncOperation;
import com.peng.herostory.login.db.IUserDao;
import com.peng.herostory.login.db.UserEntity;
import com.peng.herostory.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.util.function.Consumer;

/**
 * 登陆服务
 */
@Slf4j
public class LoginService {
    /**
     * 日志对象
     */
    static private final Logger LOGGER = LoggerFactory.getLogger(LoginService.class);

    /**
     * 单例对象
     */
    static private final LoginService _instance = new LoginService();

    /**
     * 私有化类默认构造器
     */
    private LoginService() {
    }

    /**
     * 获取单例对象
     *
     * @return 单例对象
     */
    static public LoginService getInstance() {
        return _instance;
    }

    /**
     * 用户登陆
     *
     * @param userName 用户名称
     * @param password 密码
     * @return 用户实体
     */
    public void userLogin(String userName, String password, Consumer<UserEntity> callback) {
        AsyncThreadProcessor.getInstance().process(new GetUserEntityOp(userName, password, callback));
    }


    /**
     * 更新用户的基本信息
     *
     * @param resultUserEntity
     */
    private void updateUserInfoInRedis(UserEntity resultUserEntity) {
        try (Jedis jedis = RedisUtil.getRedis()) {
            int userId = resultUserEntity.userId;
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userId", userId);
            jsonObject.put("userName", resultUserEntity.userName);
            jsonObject.put("heroAvatar", resultUserEntity.heroAvatar);
            jedis.hset("User_" + userId, "BasicInfo", jsonObject.toJSONString());
        } catch (Exception ex) {
            log.error("e:{0}", ex);
        }
    }

    private class GetUserEntityOp implements IAsyncOperation {
        private UserEntity resultUserEntity = new UserEntity();
        private String userName;
        private String password;
        private Consumer<UserEntity> callback;

        public GetUserEntityOp(String userName, String password, Consumer<UserEntity> callback) {
            this.userName = userName;
            this.password = password;
            this.callback = callback;
        }

        @Override
        public int getBindId() {
            //取用户的最后一个字符
            return userName.charAt(userName.length() - 1);
        }

        @Override
        public void doAsync() {
            log.info(Thread.currentThread().getName());
            if (null == userName ||
                    null == password) {
                return;
            }

            try (SqlSession mySqlSession = MySqlSessionFactory.openSession()) {
                // 获取 DAO 对象,
                // 注意: 这个 IUserDao 接口咱们是没有具体实现的,
                // 但如果你听过前面的课,
                // 你可能会猜到这里面究竟发生了什么... :)
                IUserDao dao = mySqlSession.getMapper(IUserDao.class);

                // 看看当前线程
                LOGGER.info("当前线程 = {}", Thread.currentThread().getName());

                // 更间用户名称获取用户实体
                UserEntity userEntity = dao.getUserByName(userName);

                if (null != userEntity) {
                    // 判断用户密码
                    if (!password.equals(userEntity.password)) {
                        // 用户密码错误,
                        LOGGER.error(
                                "用户密码错误, userId = {}, userName = {}",
                                userEntity.userId,
                                userName
                        );

                        throw new RuntimeException("用户密码错误");
                    }
                    resultUserEntity = userEntity;
                } else {
                    // 如果用户实体为空, 则新建用户!
                    UserEntity newUserEntity = new UserEntity();
                    newUserEntity.userName = userName;
                    newUserEntity.password = password;
                    newUserEntity.heroAvatar = "Hero_Shaman"; // 默认使用萨满

                    // 将用户实体添加到数据库
                    dao.insertInto(newUserEntity);
                    resultUserEntity = newUserEntity;
                }
                updateUserInfoInRedis(resultUserEntity); //更新redis中用户的基本信息

            } catch (Exception ex) {
                LOGGER.error(ex.getMessage(), ex);
            }

        }

        @Override
        public void doFinish() {
            log.info(Thread.currentThread().getName());
            callback.accept(resultUserEntity);
        }
    }
}
